package com.e3.sysmg.security.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.slf4j.Logger;
import org.springframework.transaction.annotation.Transactional;

import com.e3.core.base.DAOHelper;
import com.e3.core.base.ServiceException;
import com.e3.core.base.SessionContext;
import com.e3.core.base.SuperQueryService;
import com.e3.sysmg.audit.log.MyLoggerFactory;
import com.e3.sysmg.security.dao.ModuleDAO;
import com.e3.sysmg.security.dao.RoleDAO;
import com.e3.sysmg.security.dao.UserDAO;
import com.e3.sysmg.security.entity.ModuleEntity;
import com.e3.sysmg.security.entity.RoleEntity;
import com.e3.sysmg.security.entity.UserEntity;
import com.e3.sysmg.security.model.ModuleModel;
import com.e3.sysmg.security.model.ModuleQC;
import com.e3.sysmg.security.model.RoleModel;
import com.e3.sysmg.security.model.RoleQC;
import com.e3.sysmg.security.model.UserModel;
import com.e3.sysmg.security.model.UserQC;
import com.e3.sysmg.security.service.SecurityQueryService;

public class SecurityQueryServiceImpl extends SuperQueryService implements SecurityQueryService{
	
	Logger logger = MyLoggerFactory.getLogger(SecurityQueryServiceImpl.class);

	private ModuleDAO moduleDAO;
	
	private RoleDAO roleDAO;
	
	private UserDAO userDAO;

	private ModuleDAO getModuleDAO(){
		if(moduleDAO == null){
			moduleDAO = DAOHelper.createDAOInstance(ModuleDAO.class);
		}
		return moduleDAO;
	}
	
	private RoleDAO getRoleDAO(){
		if(roleDAO == null){
			roleDAO = DAOHelper.createDAOInstance(RoleDAO.class);
		}
		return roleDAO;
	}
	
	private UserDAO getUserDAO(){
		if(userDAO == null){
			userDAO = DAOHelper.createDAOInstance(UserDAO.class);
		}
		return userDAO;
	}
	/* (non-Javadoc)
	 * @see com.e3.sysmg.security.service.ISecurityQueryService#getModuleModelByCode(java.lang.String)
	 */
	public ModuleModel getModuleModelByCode(String code) throws ServiceException{
		ModuleEntity module = getModuleDAO().getModuleEntityByCode(code);
	
		return moduleEntityToModel(module);
	}
	
	/* (non-Javadoc)
	 * @see com.e3.sysmg.security.service.ISecurityQueryService#getModuleModelById(long)
	 */
	public ModuleModel getModuleModelById(long id) throws ServiceException{
		ModuleEntity module = getModuleDAO().getById(ModuleEntity.class, id);
	
		return moduleEntityToModel(module);
	}
	
	/* (non-Javadoc)
	 * @see com.e3.sysmg.security.service.ISecurityQueryService#getModuleModelByCodes(java.lang.String)
	 */
	public List<ModuleModel> getModuleModelByCodes(String... codes) throws ServiceException{
		List<ModuleEntity> moduleEntities = getModuleDAO().findBySingleField(ModuleEntity.class, "code", codes);
		
		if(moduleEntities!=null&&moduleEntities.size()>0){
			List<ModuleModel> moduleModels = new ArrayList<ModuleModel>(moduleEntities.size());
			for (ModuleEntity moduleEntity : moduleEntities) {
				moduleModels.add(moduleEntityToModel(moduleEntity));
			}
			return moduleModels;
		}
		
		return null;
	}
	
	/* (non-Javadoc)
	 * @see com.e3.sysmg.security.service.ISecurityQueryService#getModuleModelByIds(java.lang.Long)
	 */
	public List<ModuleModel> getModuleModelByIds(Long... ids) throws ServiceException{
		List<ModuleEntity> moduleEntities = getModuleDAO().findBySingleField(ModuleEntity.class, "id", ids);
		
		if(moduleEntities!=null&&moduleEntities.size()>0){
			List<ModuleModel> moduleModels = new ArrayList<ModuleModel>(moduleEntities.size());
			for (ModuleEntity moduleEntity : moduleEntities) {
				moduleModels.add(moduleEntityToModel(moduleEntity));
			}
			return moduleModels;
		}
		
		return null;
	}
	
	/* (non-Javadoc)
	 * @see com.e3.sysmg.security.service.ISecurityQueryService#getModuleByCondition(com.e3.sysmg.security.model.ModuleQC)
	 */
	public List<ModuleModel> getModuleByCondition(ModuleQC moduleQC) throws ServiceException{
		List<ModuleModel> moduleModels = new ArrayList<ModuleModel>();
		List<ModuleEntity> modules = getModuleDAO().getModulesByCondition(moduleQC);
		if(modules!=null){
			for (ModuleEntity module : modules) {
				moduleModels.add(moduleEntityToModel(module));
			}
		}
		return moduleModels;
	}
	
//	public List<ModuleModel> getModuleChildren(ModuleModel moduleModel) throws ServiceException{
//		String pId = moduleModel==null?"0":moduleModel.getId();
//		pId = (pId == null||pId.trim().length()==0)?"0":pId.trim();
//		List<ModuleEntity> entities = getModuleDAO().findBySingleField(ModuleEntity.class, "parentId",new Long[]{Long.parseLong(pId)});
//		
//		if(entities != null){
//			List<ModuleModel> moduleModels = new ArrayList<ModuleModel>(entities.size());
//			for (ModuleEntity entity : entities) {
//				ModuleModel moduleMd = moduleEntityToModel(entity);
//				moduleMd.setParentModule(moduleModel);
//				moduleModels.add(moduleEntityToModel(entity));
//			}
//			return moduleModels;
//		}
//		
//		return new ArrayList<ModuleModel>(0);
//	}
	
	/* (non-Javadoc)
	 * @see com.e3.sysmg.security.service.ISecurityQueryService#getModuleChildren(com.e3.sysmg.security.model.ModuleModel)
	 */
	public List<ModuleModel> getModuleChildren(ModuleModel moduleModel) throws ServiceException{
		long pId = 0;
		if(moduleModel!=null){
			pId = moduleModel.getId();	
		}
		return getModuleDAO().getModuleChildren(pId);
	}
	
	/* (non-Javadoc)
	 * @see com.e3.sysmg.security.service.ISecurityQueryService#getModulesByUserId(long)
	 */
	public List<ModuleModel> getModulesByUserId(long userId) throws ServiceException{
		
		List<ModuleEntity> modules = getModuleDAO().getModulesByUserId(userId);
		List<ModuleModel> moduleModels = new ArrayList<ModuleModel>();
		if(modules!=null){
			for (ModuleEntity module : modules) {
				moduleModels.add(moduleEntityToModel(module));
			}
		}
		return moduleModels;
	}
	
	/* (non-Javadoc)
	 * @see com.e3.sysmg.security.service.ISecurityQueryService#getModuleChildrenSize(com.e3.sysmg.security.model.ModuleModel)
	 */
	public long getModuleChildrenSize(ModuleModel moduleModel) throws ServiceException{
		long id = moduleModel.getId();
		return getModuleDAO().childrenCount(id);
	}
	
	/* (non-Javadoc)
	 * @see com.e3.sysmg.security.service.ISecurityQueryService#getAllRoles()
	 */
	public List<RoleModel> getAllRoles() throws ServiceException{
		List<RoleEntity> roleEntities = getRoleDAO().getAllRoles();
		List<RoleModel> roleModels = new ArrayList<RoleModel>();
		if(roleEntities == null||roleEntities.isEmpty()){
			return roleModels;
		}
		for (RoleEntity roleEntity : roleEntities) {
			roleModels.add(roleEntityToModel(roleEntity));
		}
		return roleModels;
	}
	
	/* (non-Javadoc)
	 * @see com.e3.sysmg.security.service.ISecurityQueryService#getRoleModules(com.e3.sysmg.security.model.RoleModel)
	 */
	@Transactional
	public List<ModuleModel> getRoleModules(RoleModel roleModel) throws ServiceException{
		if(roleModel == null){
			return new ArrayList<ModuleModel>();
		}
		long roleId = roleModel.getId();
		RoleEntity roleEntity = getRoleDAO().getById(RoleEntity.class, roleId);
		List<ModuleEntity> moduleEntites = roleEntity.getAuthedModules();
		
		if(moduleEntites!=null&&moduleEntites.size()>0){
			List<ModuleModel> moduleModels = new ArrayList<ModuleModel>(moduleEntites.size());
			for (ModuleEntity moduleEntity : moduleEntites) {
				moduleModels.add(moduleEntityToModel(moduleEntity));
			}
			return moduleModels;
		}
		return new ArrayList<ModuleModel>();
	}
	
	/* (non-Javadoc)
	 * @see com.e3.sysmg.security.service.ISecurityQueryService#getRoleParents(com.e3.sysmg.security.model.RoleModel)
	 */
	public RoleModel getRoleParents(RoleModel roleModel) throws ServiceException{
		if(roleModel == null){
			return roleModel;
		}
		long roleId = roleModel.getId();
		RoleEntity roleEntity = getRoleDAO().getById(RoleEntity.class, roleId);
		List<RoleEntity> pEntities = roleEntity.getParentRoles();
		if(pEntities!=null&&pEntities.size()>0){
			List<RoleModel> pModels = new ArrayList<RoleModel>(pEntities.size());
			for (RoleEntity re : pEntities) {
				pModels.add(roleEntityToModel(re));
			}
			roleModel.setParentRoles(pModels);
		}
		return roleModel;
	}
	
	/* (non-Javadoc)
	 * @see com.e3.sysmg.security.service.ISecurityQueryService#getRolesByCondition(com.e3.sysmg.security.model.RoleQC)
	 */
	@Transactional
	public List<RoleModel> getRolesByCondition(RoleQC roleQC) throws ServiceException{
		List<RoleEntity> roleEntities = getRoleDAO().getRolesByCondition(roleQC);
		if(roleEntities == null||roleEntities.isEmpty()){
			return new ArrayList<RoleModel>();
		}
		List<RoleModel> roleModels = new ArrayList<RoleModel>(roleEntities.size());
		for (RoleEntity roleEntity : roleEntities) {
			RoleModel roleModel = roleEntityToFullModel(roleEntity);
			roleModels.add(roleModel);
		}
		return roleModels;
	}

	private RoleModel roleEntityToFullModel(RoleEntity roleEntity) {
		RoleModel roleModel = roleEntityToModel(roleEntity);
				//get parent roles
		List<RoleEntity> pEntities = roleEntity.getParentRoles();
		if(pEntities!=null&&pEntities.size()>0){
			List<RoleModel> pModels = new ArrayList<RoleModel>(pEntities.size());
			for (RoleEntity pEntity : pEntities) {
				pModels.add(roleEntityToModel(pEntity));
			}
			roleModel.setParentRoles(pModels);
		}
		//get authed modules
		List<ModuleEntity> moduleEntities = roleEntity.getAuthedModules();
		if(moduleEntities!=null&&moduleEntities.size()>0){
			List<ModuleModel> modules = new ArrayList<ModuleModel>(moduleEntities.size());
			for (ModuleEntity mEntity : moduleEntities) {
				modules.add(moduleEntityToModel(mEntity));
			}
			roleModel.setAuthedModules(modules);
		}
		return roleModel;
	}
	
	/* (non-Javadoc)
	 * @see com.e3.sysmg.security.service.ISecurityQueryService#getAllModulesOfRole(com.e3.sysmg.security.model.RoleModel)
	 */
	@Transactional
	public List<ModuleModel> getAllModulesOfRole(RoleModel roleModel) throws ServiceException{
		if(roleModel == null){
			return new ArrayList<ModuleModel>(0);
		}
		long id = roleModel.getId();
		RoleEntity roleEntity = getRoleDAO().getById(RoleEntity.class, id);
		roleModel = roleEntityToFullModel(roleEntity);
		
		List<ModuleModel> modules = roleModel.getAuthedModules();
		if(modules == null){
			modules = new ArrayList<ModuleModel>();
		}
		
		List<RoleModel> pModels = roleModel.getParentRoles();
		if(pModels!=null&&pModels.size()>0){
			for (RoleModel rm : pModels) {
				List<ModuleModel> pModules = getAllModulesOfRole(rm);
				if(pModules!=null&&pModules.size()>0){
					for (ModuleModel moduleModel : pModules) {
						if(!modules.contains(moduleModel)){
							modules.add(moduleModel);
						}
					}
				}
			}
		}
		return modules;
	}
	
	/* (non-Javadoc)
	 * @see com.e3.sysmg.security.service.ISecurityQueryService#getUserByCondition(com.e3.sysmg.security.model.UserQC)
	 */
	@Transactional
	public List<UserModel> getUserByCondition(UserQC qc) throws ServiceException{
		List<UserEntity> entities = getUserDAO().getUserByCondition(qc);
		if(entities!=null&&entities.size()>0){
			List<UserModel> models = new ArrayList<UserModel>(entities.size());
			for (UserEntity entity : entities) {
				UserModel model = userEntityToModel(entity);
				models.add(model);
				
				List<RoleEntity> roleEntities = entity.getRoles();
				if(roleEntities!=null&&roleEntities.size()>0){
					List<RoleModel> roleModels = new ArrayList<RoleModel>(roleEntities.size());
					for (RoleEntity roleEntity : roleEntities) {
						roleModels.add(roleEntityToModel(roleEntity));
					}
					model.setRoles(roleModels);
				}
			}
			return models;
		}
		return new ArrayList<UserModel>();
	}
	
	private UserModel userEntityToModel(UserEntity entity){
		
		if(entity == null){
			return null;
		}
		
		UserModel userModel = new UserModel();
		userModel = entityToModel(userModel, entity);
		
		userModel.setId(entity.getId());
		userModel.setPassword(entity.getPassword());
		userModel.setCode(entity.getCode());
		userModel.setName(entity.getName());
		userModel.setStartDate(new Date(entity.getStartDate()));
		long endTime = entity.getEndDate();
		if(endTime>0){
			userModel.setEndDate(new Date(endTime));
		}
		
		userModel.setStatus(entity.getStatus()+"");
		
		return userModel;
	}
		
	private RoleModel roleEntityToModel(RoleEntity roleEntity){
		
		if(roleEntity == null){
			return null;
		}
		
		RoleModel roleModel = new RoleModel();
		roleModel = entityToModel(roleModel, roleEntity);
		
		roleModel.setId(roleEntity.getId());
		roleModel.setCode(roleEntity.getCode());
		roleModel.setName(roleEntity.getName());
		roleModel.setDescription(roleEntity.getDescription());
				
		return roleModel;
	}
	
	private ModuleModel moduleEntityToModel(ModuleEntity moduleEntity){
		
		if(moduleEntity == null){
			return null;
		}
		
		ModuleModel moduleModel = new ModuleModel();
		moduleModel = entityToModel(moduleModel, moduleEntity);
		
		moduleModel.setId(moduleEntity.getId());
		moduleModel.setCode(moduleEntity.getCode());
		moduleModel.setName(moduleEntity.getName());
		moduleModel.setPath(moduleEntity.getPath());
		moduleModel.setStatus(moduleEntity.getStatus());
//		moduleModel.setAuthCode(module.getAuthCode());
		
		moduleModel.setParentId(moduleEntity.getParentId());
		
		return moduleModel;
	}

	public UserModel getUserByCode(String code) throws ServiceException {
		UserQC qc = new UserQC();
		qc.setCode(code);
		qc.setCorpId(SessionContext.getCorpID());
		List<UserModel> users = getUserByCondition(qc);
		return users==null||users.isEmpty()?null:users.get(0);
	}
}
